package sg.edu.nus.iss.vmcs.machinery;

/*
 * Copyright 2003 ISS.
 * The contents contained in this document may not be reproduced in any
 * form or by any means, without the written permission of ISS, other
 * than for the purpose for which it has been supplied.
 *
 */

import java.util.Observable;
import java.util.Observer;
import sg.edu.nus.iss.vmcs.system.*;
import sg.edu.nus.iss.vmcs.util.*;
import sg.edu.nus.iss.vmcs.store.*;

/**
 *
 *
 * @version 3.0 5/07/2003
 * @author Olivo Miotto, Pang Ping Li
 */

public class MachineryController implements Observer{

	public MainController mainCtrl;
	public StoreController storeCtrl;

	private MachinerySimulatorPanel ml;
	private Door door;
	
	private MachineryState mState;	// state of MachineryController
        
	public MachineryController(MainController mctrl) {
		mainCtrl = mctrl;
		storeCtrl = mctrl.getStoreController();
		mState = new IdleState();	// set initial state to IdleState
                
//                SimulatorControlPanel scp = mainCtrl.getSimulatorControlPanel();
//		if (ml == null)
//			ml = new MachinerySimulatorPanel(scp, this);
	}

	public MainController getMainController() {
		return mainCtrl;
	}

	public void initialize() throws VMCSException {
		mState.initialize(this);
	}

	public void closeDown() {
		mState.closeDown(this);
	}

	/* ************************************************************
	 * Panel Operations
	 */

	public void displayMachineryPanel() {
		mState.displayMachineryPanel(this);
	}

	public void closeMachineryPanel() {
		mState.closeMachineryPanel(this);
	}

	/* ************************************************************
	 * Door operation
	 */

	public boolean isDoorClosed() {
		return door.isDoorClosed();
	}

	public void setDoorState(boolean state) {
		mState.setDoorState(this, state);
	}

	/* ************************************************************
	 * Display operation
	 */

	public void displayDoorState() {
		mState.displayDoorState();
	}

	// update drink stock view;
	public void displayDrinkStock() throws VMCSException {
		mState.displayDrinkStock();
	}

	// update coin stock view after transfer all cash;
	public void displayCoinStock() throws VMCSException {
		mState.displayCoinStock();
	}

	/* ************************************************************
	 * Interactions with the Store that need to update the display
	 */

	public void storeCoin(Coin c) throws VMCSException {
		mState.storeCoin(c);
	}

	public void dispenseDrink(int idx) throws VMCSException {
        //System.out.print(mState);
		mState.dispenseDrink(this, idx);
	}

	public void giveChange(int idx, int numOfCoins) throws VMCSException {
		mState.giveChange(idx, numOfCoins);
	}

        //update StoreViewer whenever there is a change in StoreItem quantity 
    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof DrinksStoreItem) {          
            if (ml == null)
                ml = new MachinerySimulatorPanel(mainCtrl.getSimulatorControlPanel(), this);
            ml.getDrinksStoreDisplay().update();
        } else if (o instanceof CashStoreItem) {
              if (ml == null)
                ml = new MachinerySimulatorPanel(mainCtrl.getSimulatorControlPanel(), this);
           ml.getCashStoreDisplay().update();
           
        }
    }
    
	/**
	 * Sets the state of this MachineryController object
	 * @param state
	 */
	protected void setState(MachineryState state) {
		mState = state;
	}
	
	/**
	 * State class for MachineryController.
	 * <p>Contains the default implementations of the methods, 
	 * most of which are empty methods.
	 * 
	 */
	private abstract class MachineryState {

		public void initialize(MachineryController mc) throws VMCSException {}
		
		public void closeDown(MachineryController mc) {
			if (ml != null)
				ml.closeDown();
			mc.setState(null);
		}
		
		public void displayMachineryPanel(MachineryController mc) {}
		
		public void closeMachineryPanel(MachineryController mc) {}
		
		public void setDoorState(MachineryController mc, boolean state) {}
		
		public void displayDoorState() {}
		
		public void displayDrinkStock() throws VMCSException {}
		
		public void displayCoinStock() throws VMCSException {}
		
		public void storeCoin(Coin c) throws VMCSException {}
		
		public void dispenseDrink(MachineryController mc, int idx) throws VMCSException {}
		
		public void giveChange(int idx, int numOfCoins) throws VMCSException {}		

	}
	
	private class IdleState extends MachineryState {		
		public void initialize(MachineryController mc) throws VMCSException {
			door = new Door();
			mc.setState(new InactiveState());	// transit to InactiveState
		}
	}
	
	private class InactiveState extends MachineryState {
		public void displayMachineryPanel(MachineryController mc) {
			SimulatorControlPanel scp = mainCtrl.getSimulatorControlPanel();
			if (ml == null)
				ml = new MachinerySimulatorPanel(scp, mc);
			ml.display();
			System.out.println("get door status:" + door.isDoorClosed());
			scp.setActive(SimulatorControlPanel.ACT_MACHINERY, false);
			mc.setState(new DoorLockedState());		// transit to DoorLockedState
		}
	}
	
	private class DoorLockedState extends MachineryState {
		public void closeMachineryPanel(MachineryController mc) {
			ml.closeDown();
			SimulatorControlPanel scp = mainCtrl.getSimulatorControlPanel();
			scp.setActive(SimulatorControlPanel.ACT_MACHINERY, true);
			mc.setState(new InactiveState());
		}
		
		public void setDoorState(MachineryController mc, boolean state) {
			//System.out.println("DoorLockedState - StoreController.setDoorState:" + state);
			door.setState(state);
			displayDoorState();
			if(state == false)
				mc.setState(new DoorOpenState());
		}
		
		public void displayDoorState() {
			ml.setDoorState(door.isDoorClosed());
		}
		
		public void displayDrinkStock() throws VMCSException {
			ml.getDrinksStoreDisplay().update();
		}
		
		public void displayCoinStock() throws VMCSException {
			ml.getCashStoreDisplay().update();
		}
		
		public void storeCoin(Coin c) throws VMCSException {
			storeCtrl.storeCoin(c);			
			ml.getCashStoreDisplay().update();
		}
		
		public void dispenseDrink(MachineryController mc, int idx) throws VMCSException {
			storeCtrl.dispenseDrink(idx, mc);			
			ml.getCashStoreDisplay().update();
		}
		
		public void giveChange(int idx, int numOfCoins) throws VMCSException {
			storeCtrl.giveChange(idx, numOfCoins);			
			ml.getCashStoreDisplay().update();
		}	
	}
	
	private class DoorOpenState extends MachineryState {
		public void closeMachineryPanel(MachineryController mc) {
			MessageDialog msg =
					new MessageDialog(null, "Please Lock the Door before You Leave");
			msg.setVisible(true);
		}
		
		public void setDoorState(MachineryController mc, boolean state) {
			//System.out.println("DoorOpenState - StoreController.setDoorState:" + state);
			door.setState(state);
			displayDoorState();
			if(state ==  true)
				mc.setState(new DoorLockedState());
		}
		
		public void displayDoorState() {
			ml.setDoorState(door.isDoorClosed());
		}
	}

}
